home *** CD-ROM | disk | FTP | other *** search
- Path: xylogics.com!not-for-mail
- From: carlson@xylogics.com (James Carlson)
- Newsgroups: comp.std.c
- Subject: Re: Q: char **foo, char *foo[], and char foo[][] ?
- Date: 18 Apr 1996 08:05:28 -0400
- Organization: Xylogics Incorporated
- Distribution: world
- Message-ID: <4l5b68$kg2@newhub.xylogics.com>
- References: <4l33ok$oo2@Sherlock.lectra.fr>
- Reply-To: carlson@xylogics.com
- NNTP-Posting-Host: newhub.xylogics.com
-
-
- In article <4l33ok$oo2@Sherlock.lectra.fr>, phil@rd.lectra.fr (Philippe Maurisset) writes:
- |> Considering the 3 following declarations:
- |>
- |> 1 - char **foo;
- |> 2 - char *foo[];
- |> 3 - char foo[][];
- |>
- [...non-working example deleted...]
- |> Can anybody help me ? Is it system-dependent ?
-
- No, it's not system-dependent, but it is context-specific.
-
- There are some rules you can follow. When you define a simple array
- (all []'s, like foo[3][9]), you can refer to it in prototypes either as
- fully-dimensioned (all []'s with constant values, like foo[3][9]), or
- with the first dimension elided (all but first [] with constant, like
- foo[][9]), or even as a simple pointer (like *foo or foo[]), although
- the dimensioning will be lost and the elements will appear as a single-
- dimension array (27 elements in this case). You may not refer to it as
- "*foo[]", either as an argument declarator or in an "extern" in a
- separate file.
-
- When you create an array of pointers (like *foo[3][2]), you can refer to
- it in prototypes either as the same type of pointer (*foo[3][2] again),
- or with the first dimension elided (*foo[][2]), or even as a simple
- pointer (**foo), though, again, you drop back to single-dimension.
-
- The pattern here is that the first set of brackets ([]) translate into
- one level of "*" in the function argument declaration, but additional
- levels of brackets do NOT add "*"s to the function argument. Thus,
- char foo[1000] and char foo[10][10][10] are stored in exactly the same
- internal format, and can be referred to in a function argument list as
- foo[1000], foo[], foo[][10][10], foo[10][10][10], or *foo.
-
- One more wrinkle to consider is that when declaring a variable, *foo is
- different from (and incompatible with) foo[], but when passed as an
- argument, they are identical. Thus, when making "extern" statements to
- refer to a variable (rather than passing as an argument list), do not
- follow the above rules, but rather declare variable exactly as
- originally defined. The only exception to that rule is that you may
- still elide the first dimension in an extern (like foo[][9]), but,
- again, you cannot choose to call this "*foo" in the extern.
-
- Instead of trying to argue about the abstract types, let's instead look
- at a hypothetical example on an imaginary machine.
-
- char **var1;
- char *var2[5];
- char var3[3][2];
-
- These three declarations could produce the following assembly code for
- our hypothetical machine (assuming 32-bit architecture, nice, simple
- system):
-
- .bss var1,4 # single char** pointer, 4 bytes
- .bss var2,20 # five char* pointers, 20 bytes
- .bss var3,6 # array of 3x2 chars, 6 bytes
-
- Note that these are extremely different. The first case declares a
- single simple pointer, which happens to be a pointer-to-a-pointer. The
- second declares a contiguous array of 5 pointers, each of which happens
- to be a pointer-to-a-char. The last example just creates a block of 6
- bytes, no pointers.
-
- Because the types are different, the compiler knows to generate
- different code for accessing each case. Let's carry this a little
- further and fetch var3[2][1], var2[2][1], and var1[2][1]. These look
- like (two register machine, "ptr" and "acc"):
-
- move (var3+5),acc # move offset 2*2+1 into accum.
-
- move (var2+8),ptr # move offset 2*4 into pointer
- move 1(ptr),acc # move offset 1 into accumul.
-
- move var3,ptr # fetch var3 (pointer)
- move 8(ptr),ptr # move offset 2*4 into pointer
- move 1(ptr),acc # move offset 1 into accumul.
-
- In the first case, the compiler uses the "var3" symbol as the location
- of the beginning of the array, and simply needs to offset out to the
- 6th location to fetch the desired character. In the second case, the
- compiler can locate var2[2] immediately; it's the second element in the
- var2 array (pointers of 4 bytes each), but then it must use the value at
- that location as a pointer to the actual array of characters, and then
- fetch offset 1 from there. In the last case, the compiler must fetch
- the contents of var3, treat it as a pointer to fetch the 2nd pointer
- value (again 4 bytes each), and then fetch offset 1 from that value.
-
- --
- James Carlson <carlson@xylogics.com> Tel: +1 617 272 8140
- Annex Interface Development / Xylogics, Inc. +1 800 225 3317
- 53 Third Avenue / Burlington MA 01803-4491 Fax: +1 617 272 2618
-